﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using Isuka.Spiritual.Auxiliaries;

namespace Isuka.Spiritual
{
    public sealed partial class ValueConvertibleRule<V, T, A>
        : IRule<T, A>
        where T : IEquatable<T>
        where A : class
    {

        public ValueConvertibleRule(IRule<T, A> rule, Func<IEnumerable<T>, V> conv)
        {
            Contract.Requires<ArgumentNullException>(rule != null, "rule");
            Contract.Requires<ArgumentNullException>(conv != null, "conv");

            Rule = rule.Rule;
            Converter = conv;
        }

        internal ValueConvertibleRule(Rules<T, A>.RuleFunc rule, Func<IEnumerable<T>, V> conv)
        {
            Contract.Requires(rule != null);
            Contract.Requires(conv != null);

            Rule = rule;
            Converter = conv;
        }

        public Func<IEnumerable<T>, V> Converter
        {
            get;
            private set;
        }

        #region IRule<T,A> メンバー

        public Rules<T, A>.RuleFunc Rule
        {
            get;
            set;
        }

        #endregion

        #region Operators

        public ValueConvertibleRule<V, T, A> this[Action<A> action]
        {
            get
            {
                Contract.Requires(action != null);
                Contract.Ensures(Contract.Result<ValueConvertibleRule<V, T, A>>() != null);

                return new ValueConvertibleRule<V, T, A>(Rule.Act(action), Converter);
            }
        }

        public ValueConvertibleRule<V, T, A> this[Action<A, V> action]
        {
            get
            {
                Contract.Requires(action != null);
                Contract.Ensures(Contract.Result<ValueConvertibleRule<V, T, A>>() != null);

                return new ValueConvertibleRule<V, T, A>(Rule.Act(action, Converter), Converter);
            }
        }

        #endregion

        #region ContractInvariantMethod

        [ContractInvariantMethod]
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
        private void ObjectInvariant()
        {
            Contract.Invariant(Converter != null);
        }

        #endregion
    }
}
